Tengo el siguiente problema (g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4):
Cuando uso _mm256_slli_si256() directamente, como:
__m256i x = _mm256_set1_epi8(0xff); x = _mm256_slli_si256(x, 3); el código compila sin problema ( g++ -Wall -march=native -O3 -o shifttest shifttest.C ).
Sin embargo, si lo envuelvo en una función
__m256i doit(__m256i x, const int imm) { return _mm256_slli_si256(x, imm); }el compilador se queja de que
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h: In function '__m256i doit(__m256i, int)': /usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h:651:58: error: the last argument must be an 8-bit immediate return (__m256i)__builtin_ia32_pslldqi256 (__A, __N * 8);independientemente de si la función se utiliza o no.
Esto no puede ser un problema con el operando inmediato, ya que la función doit() compila si uso, por ejemplo _mm256_slli_si32(x, imm) en su lugar, y _mm256_slli_si32() también requiere un operando inmediato.
Hay un informe de error relacionado en
https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=54825
pero es bastante antiguo (2012) y se relaciona con gcc 4.8.0, por lo que pensé que el parche ya se habría incorporado a g ++ 4.8.4.
¿Hay alguna solución alternativa a este problema?
El argumento que indica el número de bits a desplazar debe ser una constante de tiempo de compilación, ya que se codifica como un valor inmediato en la instrucción (es decir, no se carga desde un registro; el valor de desplazamiento real forma parte de la codificación de la instrucción). Siempre y cuando lo uses directamente, así:
__m256i x = _mm256_set1_epi8(0xff); x = _mm256_slli_si256(x, 3);luego, el compilador ve el valor de cambio como una constante de tiempo de compilación, 3. Sin embargo, cuando está en el contexto de su función de ajuste:
__m256i doit(__m256i x, const int imm) { return _mm256_slli_si256(x, imm); } el compilador no tiene forma de inferir el valor de imm en el momento de la compilación, que es necesario para sintetizar la instrucción shift. El hecho de que imm sea un const int no significa que su valor se conozca en tiempo de compilación, solo que la semántica del lenguaje no permite modificarlo dentro del alcance de la función doit() .
Es posible que si el compilador introdujera doit() , entonces podría determinar estáticamente el valor de imm y, por lo tanto, compilar con éxito, pero eso podría ser ir demasiado lejos.
Si está utilizando C++, otra opción sería hacer de doit() una plantilla de función con un argumento que indique el tamaño del cambio, como este:
template <int Shift> __m256i doit(__m256i x) { return _mm256_slli_si256(x, Shift); }El problema se debe a que su función es pública (es decir, puede ser llamada por funciones en otros módulos de C/C++). Si lo declara como static (o inline ), el compilador no generará código para esta función y no obtendrá un error.